#!/usr/bin/perl

use IO::Socket;
use threads('yield', 'stack_size' => 4096*1024);
use strict;

# Author : Nipuna Perera

############################################################################
#			CONFIGURATIONS STARTS HERE
############################################################################

#set your proxy server and port here
my $proxy_host = 192.168.0.105;
my $proxy_port = 3128;

#this timeout to terminate proxy connections after getting the requests.
#by default this keeping 5 seconds.
my $proxy_timeout = 30;

#if you  set this to 0, that means this application trying to connect with parent 
#proxy server, if you set this to 1, that means this application trying to
#connect with the peer directly
my $no_proxy = 1;

#$hostname is the wild card for access
#if you set this as 192.0.0.0, 
#it will allow only for people from 192.0.0.0 network
#if you set this as 0.0.0.0, it will allow to all.
my $hostname = "0.0.0.0";

#server listning port number 
my $port = 2020;

#this time out is for close the sever connection if client requests were not 
#there, put this quite high
my $timeout = 60*60*24;

#set the path of log file here.
my $log_file = "simple_proxy.log";
############################################################################
my $new_sock;
my $remote_host;
my $count =0;


sub number_gen {
        my @numbers;
        my $i = $_[1];
        while ( $i < $_[0] ){
                if ( $i < 10 ){
                        $numbers[$i]="0".$i;
                }else{
                        $numbers[$i]=$i;
                }
                #print "local :".$numbers[$i]."\n";
                $i++;
        }
        return @numbers;
}

sub get_time {
	my $logtime;
	my @days= number_gen(32,1);
	my @months=number_gen(13,1);
	my @mins=number_gen(60,0);
	my @hours=number_gen(24,0);
	my @secs=number_gen(60,0);
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
						 = localtime(time);
	$logtime=($year+1900)."-".$months[($mon+1)]."-".$days[$mday].
			" ".$hours[$hour].":".$mins[$min].":".$secs[$sec]; 
	return $logtime;
}

sub logging {
	my $time = get_time;
	my $log = shift;
	print $time." "."[TC:".$count."] ".$log;
}

sub get_request {
	my $request_data =  shift;
	my $peer_host;
	my $peer_port;
	logging "Sending request : ".$remote_host."\n";
	if ( $no_proxy == 1 ){
		my @host = split(/\//,$remote_host);
		my @peer = split(/:/,$host[2]);
		$peer[1] = 80 unless $peer[1];
		$peer_host = $peer[0];
		$peer_port = $peer[1];
		logging "Directly connecting with peer : "
				.$peer_host.":".$peer_port."\n";
	}else{
                $peer_host = $proxy_host;
                $peer_port = $proxy_port;
		logging "Connecting to peer via proxy : "
				.$peer_host.":".$peer_port."\n";
	}
	#opening remote proxy connection
	logging "Opening the client connection\n";
	my $socket_client = IO::Socket::INET->new(
                                 PeerAddr => $peer_host,
                                 PeerPort => $peer_port,
                                 Proto => 'tcp',
				 Timeout => $proxy_timeout
        )or logging "Could not create proxy socket: $!\n";

	binmode $socket_client;

	#sending request data to proxy
	print $socket_client $request_data;

	my ($response_param, $content_length);

	#getting response data from proxy (line by line)
	while (<$socket_client>){
		#sending data back to client
		print $new_sock $_;
		my @http = grep {/^HTTP*/} $_;
		my @length = grep {/^Content-Length*/} $_;
		my $content_length_size = scalar @length;
		my $http_size =  scalar @http;
		if ( $http_size > 0 ){
			$http[0] =~s/\n|\r/ /;
			$response_param = $http[0];
			logging "Response received : ".$response_param;
		}
		if ( $content_length_size > 0 ){
			$length[0] =~ s/\n|\r/ /;
			$content_length = $length[0];			
			logging "Response received : ".$content_length;
		}
	}
	logging "Closing the peer connections...\n";
	#closing the remote proxy connection
	close $socket_client;

	#closing the client connection
	#print $new_sock "\r";
	logging "Closing the browser connections.. \n";
	close $new_sock;
}

sub get_data {
	my $data;
	my $size;
	my $client = $new_sock;
	while (<$client>){
		#collecting the request to $data
		$data=$data.$_;
		my @get_line = grep {/^GET*|^POST*|^CONNECT*/} $_;
		$size = scalar @get_line;
		if ( $size > 0 ){
			my @get = split(/ /,$get_line[0]);
			$remote_host=$get[1];
		}
		my @input=grep {/^\r/} $_; 
		$size = scalar @input;
		if ( $size > 0 ){
			logging "Sending data to get_request\n";
			get_request $data;
			logging "Data has retrived...\n";
		}
	}
}
#################################################################################
#		End of the sub routings..
#################################################################################
my $sock = new IO::Socket::INET ( 
        LocalHost => $hostname, 
        LocalPort => $port, 
        Proto => 'tcp', 
        Listen => 50, 
        Reuse => 10,
	Timeout => $timeout 
) or logging "Could not create socket: $!\n";

binmode $sock;

logging "Server Socket has Open in : ". $port."\n";
while ($new_sock = $sock->accept()){
	$count++;
	my $t = threads->new(\&get_data,$new_sock);
	$t->detach;
}
#closing the server
close $sock;
##################################################################################
